﻿
using Dapper;

using HBase;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Reflection.Emit;
using System.Reflection.Metadata;
using System.Transactions;

namespace hCommand {
    /**
   *┌────────────────────────────────────────────────┐
   *│　描    述：Component                                                    
   *│　作    者：sgj                                              
   *│　版    本：1.0                                              
   *│　创建时间：2020/9/2 11:28:16                        
   *└────────────────────────────────────────────────┘
   **/
    public abstract class AbsTaskEngine : AbsLocEngine {

        /// <summary>
        /// 移库任务
        /// </summary>

        /// <returns></returns>
        public long abdicationMove(long goodDiff, AbsCoreStock cs, List<long> deepScrList, IDbConnection conn, IDbTransaction trans) {
            //将该浅货位的货物移动到该浅货位同组下的空货位  csdList[0].rLoctionId==null ? 0: csdList[0].rLoctionId
            var whLoc = conn.GetById<CoreWhLoc>(cs.locId, trans);
            if (whLoc == null) {
                throw new Exception(cs.boxCode + "不在库存");
            }
            List<CoreWhLoc> locList = getLoc4SelectIn(whLoc.areaId, whLoc.moveGroup, conn, trans);
            for (int i = 0; i < locList.Count; i++) {
                if (deepScrList.Contains(locList[i].scr)) {
                    locList.RemoveAt(i);
                    i--;
                }
            }
            CoreWhLoc des = I18nConfig.select(locList, cs.deepDiff, cs );//每个moveGroup 必须有一个空货位共移库
            int desId = TaskNoUtil.virtual_Loc;
            if (des != null) {
                desId = (int)des.id;
            }

            return locMoreMove(cs, desId, conn, trans, goodDiff);
        }
        
        public TaskResDto locLessMove(IDbConnection conn, IDbTransaction trans, int from, int des, List<TaskResDto> relays, string waveNo, string info = "") {
            long taskId = InsertTask(0, from, des, conn, trans, 0, "", waveNo, info, BussType.自定义);
            string relyId = "";
            foreach (var dto in relays) {
                relyId += dto.paramId + ",";
            }
            relyId = relyId.Substring(0, relyId.Length - 1);
            long paramId = InsertCoreTaskParam(conn, trans, 0,"" , taskId, from, des, TaskParamType.托盘搬运, relyId);
            return new TaskResDto() { taskId = taskId, paramId = paramId };
        }

        public long locMoreMove(AbsCoreStock cs, long desId, IDbConnection conn, IDbTransaction trans, long goodDiff = 0) {
            //将该浅货位的货物移动到该浅货位同组下的空货位  csdList[0].rLoctionId==null ? 0: csdList[0].rLoctionId
            var whLoc = conn.GetById<CoreWhLoc>(cs.locId, trans);
            if (whLoc == null) {
                throw new Exception(cs.boxCode + "不在库存");
            }
            long taskId = InsertTask(goodDiff, cs.locId, desId, conn, trans, cs.id, cs.boxCode, "0", null, BussType.移库);
            String content = getContent(conn, trans, cs, desId);

            long taskParamId = moveCoreTaskParam(conn, trans, content, taskId, cs.locId, (int)desId, "");
            UpdateStock(conn, trans, cs.id, StockStatus.移动中);

            UpdataWhLoc(conn, trans, cs.locId, goodDiff);
            UpdataWhLoc(conn, trans, desId, goodDiff);
            return taskParamId;
        }
        public virtual String getContent(IDbConnection conn, IDbTransaction trans,AbsCoreStock cs, long desId) {
            return "";
        }



        public TaskResDto createOutTask(long goodDiff, string info, IDbConnection conn, IDbTransaction trans, AbsCoreStock cs, int des, string waveNo, string relay = "", int bussType = BussType.自动出库, string pc = "") {

            long taskId = InsertTask(goodDiff, cs.locId, des, conn, trans, cs.id, cs.boxCode, waveNo, info, bussType);
            long paramTaskId = moveCoreTaskParam(conn, trans, pc, taskId, cs.locId, des, relay);
            UpdateStock(conn, trans, cs.id, StockStatus.移动中);

            UpdataWhLoc(conn, trans, cs.locId, goodDiff);
            return new TaskResDto() { taskId = taskId, paramId = paramTaskId };
        }
       

        /// <summary>
        /// 下发入库任务
        public TaskResDto createInTask(long goodDiff, AbsCoreStock cs, int des, IDbConnection conn, IDbTransaction tran, String relay = "", string waveNo = "", string info = null, int bussType = BussType.自动入库, string pc = "") {
            if (0 == des || null == cs) {
                throw new Exception(cs.id + " 入库任务下发失败！");
            }
            if (string.IsNullOrEmpty(waveNo)) {
                waveNo = cs.id + "";
            }

            long taskId2 = InsertTask(goodDiff, cs.locId, des, conn, tran, cs.id, cs.boxCode, waveNo, info, bussType);
            long paramTaskId = moveCoreTaskParam(conn, tran, pc, taskId2, cs.locId, des, relay);
            UpdateStock(conn, tran, cs.id, StockStatus.移动中);
            UpdataWhLoc(conn, tran, des, goodDiff);
            return new TaskResDto() { taskId = taskId2, paramId = paramTaskId };
        }
 
        public TaskResDto createPkTask(long goodDiff, IDbConnection conn, IDbTransaction tran,
          AbsCoreStock cs, int des, string waveNo, string info = null, string relay = "", string pc = "") {
            int src = cs.locId;
            long taskId2 = InsertTask(goodDiff, src, src, conn, tran, cs.id, cs.boxCode, waveNo, info, BussType.盘库);
            long paramTaskId = moveCoreTaskParam(conn, tran, pc, taskId2, src, des, relay);
            UpdateStock(conn, tran, cs.id, StockStatus.盘库中);

            UpdataWhLoc(conn, tran, src, goodDiff);
            return new TaskResDto() { taskId = taskId2, paramId = paramTaskId };
        }


        public virtual int taskBussType(int bussType) {
            return bussType;
        }

        public long InsertTask(long goodDiff, int start, long des, IDbConnection con, IDbTransaction tran,
          long stockId, string boxCode, string waveNo, string info, int bussType) {

            CoreTask task = new CoreTask();
          
            task.stockId = stockId;
            task.boxCode = boxCode;
            task.Status = (int)CoreTaskStatus.执行中;
           
            task.bussType = taskBussType(bussType);
            task.src = start;
            task.des = (int)des;
           
            task.waveNo = waveNo;
            task.goodDiff = goodDiff;
            if (string.IsNullOrEmpty(info)) {
                task.info = createCoreTaskInfo(task);
            } else {
                task.info = info;
            }
            con.InsertNoNull(task, tran);
            return task.id;
        }



        virtual protected string createCoreTaskInfo(CoreTask task) {

            return string.Format("从{0}到{1}", stnToCrane(task.src), stnToCrane(task.des));
        }
        protected virtual string stnToCrane(long loc) {
            if (I18nConfig.isLoc(loc)) {
                return (loc + 10000) / 20000 + "号垛机" + loc;
            } else {
                return loc.ToString();
            }
        }
        public long InsertCoreTaskParam(IDbConnection Connection, IDbTransaction transaction, long stockDetailId, string content, long taskId, int src, int des, TaskParamType paramType, string relyId="", CoreTaskParamStatus status = CoreTaskParamStatus.可以接收任务) {
            //任务明细添加
            CoreTaskParam param = new CoreTaskParam();
        
            param.stockDetailId = stockDetailId;
            param.taskId = taskId; //task.id
            param.status = (int)status;//新建状态
            param.src = src;
            param.cStn = param.src;
            param.des = des;
            param.taskNo = TaskNoUtil.getTaskNo(Connection, transaction);
            param.relyParamId = relyId;
            param.param = content;
            param.type = (byte)paramType;
   
            Connection.InsertNoNull(param, transaction);
            return param.id;
        }

    


        public long moveCoreTaskParam(IDbConnection Connection, IDbTransaction transaction, string content, long taskId, int src, int des, string relyId) {
            //任务明细添加
            return InsertCoreTaskParam(Connection, transaction, 0, content, taskId, src, des, TaskParamType.托盘搬运, relyId, CoreTaskParamStatus.可以接收任务);
        }
        public void check<CS>(CS cs, List<CoreTaskParam> coreTaskParam) {
            foreach (CoreTaskParam p in coreTaskParam) {
                if (p.status == (int)CoreTaskParamStatus.执行完成) {
                    throw new Exception("任务过程" + p.id + "已经完成,无法删除任务");
                }
            }
        }
        public List<CoreTaskParam> GetListByTaskId(IDbConnection conn, IDbTransaction tran, long taskId) {
            string sql = "select * from Core_task_param where task_Id=@taskId";
            return conn.Query<CoreTaskParam>(sql, new { taskId }, tran).ToList();
        }
        public CoreTask getCoreTask(IDbConnection Connection, IDbTransaction transaction, long taskId) {
            string sql = @"select * from Core_task where id=@taskId ";
            List<CoreTask> list = Connection.Query<CoreTask>(sql, new {
                taskId
            }, transaction).ToList();
            if (list.Count < 1) {
                throw new Exception(taskId + " 任务不存在!");
            }
            return list[0];
        }

        public bool UpdateStock(IDbConnection Connection, IDbTransaction transaction, long stockId, StockStatus status) {
            string sql = "update  Core_Stock set status=@status , change_Time=sgj_get_sys_now where id=@Id";
            int count = Connection.Execute(sql, new { id = stockId, status = (int)status }, transaction); 
            return true;
        }


        public long getRelayId<CS>(IDbConnection conn, IDbTransaction tran, CS cs, List<long> deepScrList) where CS : AbsCoreStock {
            long relyId = 0;
            var whLoc = conn.Get<CoreWhLoc>(cs.locId, tran);
            if (whLoc == null || whLoc.deepIndex == 1) {
                return relyId;
            }
            //浅货位,存在入库中任务时
            var whLocShallow = conn.GetAll<CoreWhLoc>("AND scr=@scr and deep_Index=1", whLoc, tran).FirstOrDefault();
            if (whLocShallow == null) {
                throw new Exception("未找到该浅货位信息,无法进行深货位取货!");
            }
            if (whLocShallow.countStock == 0) {
                return 0;
            }
            string sql = "select * from  Core_Stock where loc_Id=@locId";
            CS csShallow = conn.Query<CS>(sql, new { locId = whLocShallow.id }, tran).FirstOrDefault();
            if (csShallow == null) {
                throw new Exception("浅货位货位 " + whLocShallow.id + " 的货位状态有误，不能进行移库");
            }
            //whLocShallow 不用判断为空，为空表示数据库 库位信息不完整

            if (whLocShallow.workingCount() == 0) {
                long goodDiff = csShallow.deepDiff;
                relyId = abdicationMove(goodDiff, csShallow,  deepScrList, conn, tran);
                if (relyId == 0) {
                    throw new Exception("移库浅货位失败" + whLocShallow.id);
                }
                return relyId;
            } else {
                if (whLocShallow.countIn > 0) {
                    throw new Exception("浅货位正在入库,无法进行深货位取货!");
                } else {
                    relyId = getRelyParamId(conn, tran, csShallow.id, whLocShallow);
                }
            }
            return relyId;
        }

        long getRelyParamId(IDbConnection conn, IDbTransaction tran, long stockId, CoreWhLoc loc) {
            string sql = "select max(id) from core_task where stock_id=@stockId    ";
            var id = conn.QueryUnique<long>(sql, new { stockId }, tran);

            string paramSql = "SELECT max(id) FROM  core_task_param  where task_Id = @id";
            long relyId = conn.QueryUnique<long>(paramSql, new { id }, tran);
            CoreTaskParam param = conn.GetById<CoreTaskParam>(relyId, tran);
            if (param.des == loc.id) {
                throw new Exception("浅货位正在入!");
            }
            return relyId;
        }
    }
}

